<template>
  <div class="storyboard-image-panel">
    <!-- <div
      class="batch-actions"
      v-if="hasSelectedShots"
    >
      <el-button
        type="danger"
        @click="clearSelection"
      >
        取消选择
      </el-button>
      <span class="selection-info">已选择 {{ selectedShots.length }} 个分镜</span>
    </div> -->

    <el-table
      :data="shots"
      style="width: 100%"
      max-height="600"
      class="storyboard-table"
      v-loading="loading"
      @selection-change="handleSelectionChange"
    >
      <el-table-column
        type="selection"
        width="55"
        align="center"
      />

      <el-table-column
        label="序号"
        width="60"
        align="center"
      >
        <template #default="{ $index }">
          {{ $index + 1 }}
        </template>
      </el-table-column>

      <el-table-column
        label="原文描述"
        min-width="180"
        align="center"
      >
        <template #default="{ row }">
          <div
            class="text-content"
            style="text-align: center;"
          >
            {{ row.originalText }}
          </div>
        </template>
      </el-table-column>
      <el-table-column
        label="画面描述词"
        min-width="220"
        align="center"
      >
        <template #default="{ row }">
          <div
            class="prompt-content"
            style="text-align: center;"
          >
            <el-input
              v-model="row.englishPrompt"
              type="textarea"
              :rows="3"
              :disabled="row.generating"
              resize="none"
              class="prompt-input"
            />
            <el-button
              type="info"
              size="small"
              @click="handleRegeneratePrompt(row)"
              :loading="row.regeneratingPrompt"
              :disabled="row.generating || row.regeneratingPrompt"
              class="regenerate-button"
            >
              重新生成描述词
            </el-button>
          </div>
        </template>
      </el-table-column>

      <!-- 新增：角色标签列 -->
      <el-table-column
        label="角色标签"
        min-width="180"
        align="center"
      >
        <template #header>
          <div class="column-header-with-action">
            <span>角色标签</span>
            <el-tooltip content="刷新角色列表" placement="top">
              <el-button
                type="primary"
                :icon="RefreshRight"
                circle
                size="small"
                @click="refreshCharacters"
                class="refresh-button"
              />
            </el-tooltip>
          </div>
        </template>
        <template #default="{ row }">
          <div class="tags-content">
            <el-select
              v-model="row.characterTags"
              multiple
              filterable
              :disabled="row.generating"
              placeholder="选择角色"
              style="width: 100%"
              @change="handleCharacterTagsChange(row)"
            >
              <el-option
                v-for="char in characters"
                :key="char.id"
                :label="char.name"
                :value="char.name"
              >
                <div class="character-option">
                  <span>{{ char.name }}</span>
                  <el-tooltip
                    v-if="char.description"
                    :content="char.description"
                    placement="right"
                    :show-after="500"
                  >
                    <el-icon>
                      <InfoFilled style="margin-left: 5px; color: #909399; cursor: help;" />
                    </el-icon>
                  </el-tooltip>
                </div>
              </el-option>
            </el-select>
          </div>
        </template>
      </el-table-column>

      <el-table-column
        label="本镜配图"
        width="220"
        align="center"
      >
        <template #default="{ row, $index }">
          <div
            class="image-preview"
            v-if="row.image"
          >
            <div
              class="image-container"
              :class="{ 'selected-image': row.selected }"
              :data-shot-id="$index"
            >
              <el-image
                :src="`data:image/png;base64,${row.image}`"
                :preview-src-list="[`data:image/png;base64,${row.image}`]"
                :initial-index="0"
                fit="contain"
                style="width: 100%; height: 100%; cursor: zoom-in"
                :preview-teleported="true"
                :hide-on-click-modal="false"
                :zoom-rate="1.2"
                :preview-options="{
                    zoom: true,
                    closeOnPressEscape: true,
                    maskClosable: false
                  }"
              />
              <div
                class="selection-indicator"
                v-if="row.selected"
              >
                <el-icon>
                  <Check />
                </el-icon>
              </div>
              <div
                class="selection-control"
                @click.stop="toggleImageSelection(row)"
                title="选择/取消选择"
              >
                <el-icon>
                  <Check />
                </el-icon>
              </div>
              <div
                class="completed-badge"
                v-if="row.image"
              >已完成
              </div>
            </div>
            <div class="image-actions">
              <el-button
                type="primary"
                @click="handleGenerate(row, 1)"
                :loading="row.generating"
                :disabled="!sdServiceAvailable || batchGenerating"
              >
                生成图片
              </el-button>
              <el-button
                type="primary"
                @click="handleGenerate(row,0)"
                :loading="row.generating"
                :disabled="!sdServiceAvailable || batchGenerating"
              >
                批量生成
              </el-button>
            </div>
            <!-- 缩略图预览区 -->
            <div
              class="thumbnails-preview"
              v-if="row.variantImages && row.variantImages.length > 0"
            >
              <div
                v-for="(image, idx) in row.variantImages"
                :key="idx"
                class="thumbnail"
                :class="{'active-thumbnail': idx === row.selectedThumbnailIndex}"
                @click="switchMainImage(row, idx)"
                :title="'切换到图片 #' + (idx + 1)"
              >
                <el-image
                  :src="`data:image/png;base64,${image}`"
                  fit="cover"
                />
                <div
                  class="thumbnail-selected"
                  v-if="idx === row.selectedThumbnailIndex"
                >
                  <el-icon>
                    <Check />
                  </el-icon>
                </div>
              </div>
            </div>
          </div>
          <div
            v-else
            class="generate-placeholder"
          >
            <el-button
              type="primary"
              @click="handleGenerate(row,1)"
              :loading="row.generating"
              :disabled="!sdServiceAvailable || batchGenerating"
            >
              生成图片
            </el-button>
            <el-button
              type="primary"
              @click="handleGenerate(row,0)"
              :loading="row.generating"
              :disabled="!sdServiceAvailable || batchGenerating"
            >
              批量生成
            </el-button>
          </div>
        </template>
      </el-table-column>
      <el-table-column
        label="操作"
        width="150"
        fixed="right"
        align="center"
      >
        <template #default="{ row, $index }">
          <div class="operations">
            <el-button-group>
              <el-tooltip content="修改" placement="top">
                <el-button
                  type="primary"
                  :icon="Edit"
                  @click="handleEdit(row)"
                  :disabled="row.generating"
                />
              </el-tooltip>
              <el-tooltip content="删除" placement="top">
                <el-button
                  type="danger"
                  :icon="Delete"
                  @click="handleDelete($index)"
                  :disabled="row.generating"
                />
              </el-tooltip>
            </el-button-group>
            <!-- 添加向上和向下拆分按钮 -->
            <div class="merge-actions" style="margin-top: 8px;">
              <el-button-group>
                <el-tooltip content="向上合并" placement="top">
                  <el-button
                    type="primary"
                    @click="handleMergeUp($index)"
                    :disabled="$index === 0 || row.generating"
                  >
                    <el-icon style="vertical-align: middle">
                      <CaretTop />
                    </el-icon>
                  </el-button>
                </el-tooltip>
                <el-tooltip content="向下合并" placement="top">
                  <el-button
                    type="primary"
                    @click="handleMergeDown($index)"
                    :disabled="$index === props.shots.length - 1 || row.generating"
                  >
                    <el-icon style="vertical-align: middle">
                      <CaretBottom />
                    </el-icon>
                  </el-button>
                </el-tooltip>
              </el-button-group>
            </div>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页控制器 -->
    <div class="pagination-container" v-if="props.totalShots > 0">
      <el-pagination
        v-model:current-page="props.currentPage"
        v-model:page-size="props.pageSize"
        :page-sizes="[5, 10, 20, 50]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="props.totalShots"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
    <div
      class="batch-actions"
      v-if="shots.length > 0"
    >
      <el-button
        type="primary"
        @click="handleBatchGenerate"
        :loading="batchGenerating"
        :disabled="!sdServiceAvailable || batchGenerating"
      >
        批量生成
      </el-button>
      <el-button
        type="success"
        @click="handleExport"
        :disabled="!hasGeneratedImages"
      >
        {{ hasSelectedShots ? '导出选中分镜' : '导出全部分镜' }}
      </el-button>
    </div>


    <el-dialog
      v-model="exportDialogVisible"
      :title="hasSelectedShots ? '导出选中分镜' : '导出全部分镜'"
      width="30%"
    >
      <el-form>
        <el-form-item label="导出目录名称">
          <el-input
            v-model="exportFolderName"
            placeholder="请输入导出目录名称"
          />
        </el-form-item>
      </el-form>
      <template #footer>
          <span class="dialog-footer">
            <el-button @click="exportDialogVisible = false">取消</el-button>
            <el-button
              type="primary"
              @click="confirmExport"
              :loading="exporting"
            >
              确认导出
            </el-button>
          </span>
      </template>
    </el-dialog>

    <!-- 悬浮进度显示组件 -->
    <div
      class="floating-progress"
      v-if="batchProgress.visible"
    >
      <div class="progress-header">
        <span class="progress-title">批量生成进度</span>
        <el-button
          type="text"
          @click="batchProgress.visible = false"
          class="close-button"
        >
          <el-icon>
            <Close />
          </el-icon>
        </el-button>
      </div>
      <div class="progress-content">
        <el-progress
          :percentage="Math.floor((batchProgress.current / batchProgress.total) * 100)"
          :status="batchProgress.failed > 0 ? 'exception' : ''"
          :format="(percentage) => `${percentage}%`"
        />
        <div class="progress-stats">
          <span>总计: {{ batchProgress.total }}</span>
          <span>当前: {{ batchProgress.current }}</span>
          <span class="success-count">成功: {{ batchProgress.success }}</span>
          <span class="failed-count" v-if="batchProgress.failed > 0">失败: {{ batchProgress.failed }}</span>
        </div>
        <div class="failed-shots" v-if="batchProgress.failedShots.length > 0">
          <div class="failed-title">失败分镜:</div>
          <div class="failed-list">
            <div v-for="(shot, index) in batchProgress.failedShots" :key="index" class="failed-item">
              {{ shot }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { Edit, Delete, RefreshRight, Check, InfoFilled, Close } from '@element-plus/icons-vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import { exportApi } from '@/services/export'
import { characterApi } from '@/services/character'

// 使用统一的Shot类型定义
import { Shot } from '@/types'

const props = defineProps<{
  shots: Shot[]
  sdServiceAvailable: boolean
  loading?: boolean
  currentModel?: string // 添加当前选择的模型属性
  totalShots: number // 添加总分镜数量
  currentPage: number // 添加当前页码
  pageSize: number // 添加每页显示数量
}>()

const loading = ref(false)

const emit = defineEmits<{
  (e: 'update:shots', shots: Shot[]): void
  (e: 'generate-image', shot: Shot): void
  (e: 'generate-variants', shot: Shot): void
  (e: 'regenerate-prompt', shot: Shot, model?: string): void
  (e: 'export-selected', shots: Shot[]): void
  (e: 'size-change', size: number): void
  (e: 'current-change', page: number): void
}>()

const batchGenerating = ref(false)
const selectedShots = ref<Shot[]>([])
const exportDialogVisible = ref(false)
const exportFolderName = ref('')
const exporting = ref(false)

// 批量生成进度状态
const batchProgress = ref({
  visible: false,
  total: 0,
  current: 0,
  success: 0,
  failed: 0,
  failedShots: [] as string[]
})

// 角色列表
const characters = ref<any[]>([])

const hasGeneratedImages = computed(() => {
  return props.shots.some((shot) => shot.image)
})

const hasSelectedShots = computed(() => selectedShots.value.length > 0)

// 处理页码变化
const handleCurrentChange = (page: number) => {
  emit('current-change', page)
}

// 处理每页显示数量变化
const handleSizeChange = (size: number) => {
  emit('size-change', size)
}

// 加载角色列表
const loadCharacters = async () => {
  try {
    characters.value = await characterApi.initCharacters()
    console.log('角色列表加载成功:', characters.value.length, '个角色')
  } catch (error) {
    console.error('加载角色列表失败:', error)
    ElMessage.error('加载角色列表失败')
  }
}

// 刷新角色列表
const refreshCharacters = async () => {
  try {
    const oldLength = characters.value.length
    characters.value = await characterApi.initCharacters()
    const newLength = characters.value.length

    if (newLength !== oldLength) {
      ElMessage.success(`角色列表已更新，当前共有${newLength}个角色`)
    } else {
      ElMessage.info('角色列表已刷新')
    }

    // 更新所有分镜中的角色标签，移除已删除的角色
    const characterNames = characters.value.map(char => char.name)
    props.shots.forEach(shot => {
      if (shot.characterTags?.length) {
        shot.characterTags = shot.characterTags.filter(tag => characterNames.includes(tag))
      }
    })
    emit('update:shots', [...props.shots])
  } catch (error) {
    console.error('刷新角色列表失败:', error)
    ElMessage.error('刷新角色列表失败')
  }
}

const handleGenerate = async (shot: Shot, batch_size?: number) => {
  shot.batch_size = batch_size
  // 确保generating属性已初始化
  if (shot.generating === undefined) {
    shot.generating = false
  }

  if (shot.generating) return
  const index = props.shots.indexOf(shot)

  // 即使在当前页面找不到该shot（可能因为分页切换），也继续处理
  // 这样可以确保批量生成在切换分页后仍然能继续进行
  let shotToUpdate = shot
  let shotIndex = index

  if (index === -1) {
    // 如果在当前页面找不到该shot，尝试在所有shots中查找
    // 注意：这里假设父组件中有一个完整的shots列表
    console.log('当前页面找不到该shot，可能已切换分页')
    shotToUpdate = shot
    shotIndex = -1 // 标记为不在当前页面
  } else {
    shotToUpdate = props.shots[index]
    shotIndex = index
  }

  // 记录生成前的图片状态，用于后续比较
  const originalImage = shotToUpdate.image

  // 确保variantImages数组已初始化
  if (!shotToUpdate.variantImages) {
    shotToUpdate.variantImages = []
  }

  // 创建shot的副本并设置generating状态
  const updatedShot = { ...shotToUpdate, generating: true }

  // 如果shot在当前页面，更新UI
  if (shotIndex !== -1) {
    props.shots[shotIndex] = updatedShot
    emit('update:shots', [...props.shots])
  }

  // 将checkCount变量移到try块外部，使其在finally块中可访问
  let checkCount = 0
  const maxChecks = 60 // 增加最大检查次数到60次，约60秒
  let imageGenerated = false

  try {
    // 获取选中角色的描述词和性别信息
    let characterPrompts = ''
    let genderPrefix = ''

    if (shot.characterTags?.length) {
      const selectedCharacters = characters.value.filter((char) =>
        shot.characterTags?.includes(char.name)
      )

      // 统计男性和女性角色数量
      const maleCount = selectedCharacters.filter(char => char.gender === 'male').length
      const femaleCount = selectedCharacters.filter(char => char.gender === 'female').length
      const totalCount = maleCount + femaleCount

      // 根据角色性别生成前缀，使用Stable Diffusion能识别的格式
      if (totalCount > 0) {
        if (maleCount > 0 && femaleCount > 0) {
          // 男女混合场景，使用明确的人数和性别描述
          genderPrefix = `${totalCount}people\(${maleCount}boy and ${femaleCount}girl\),`
        } else if (maleCount > 0) {
          // 纯男性场景
          genderPrefix = maleCount > 1 ? `${maleCount}people\(${maleCount}boys\),` : `1people\(1boy\),`
        } else if (femaleCount > 0) {
          // 纯女性场景
          genderPrefix = femaleCount > 1 ? `${femaleCount}people\(${femaleCount}girls\),` : `1people\(1girl\),`
        }
      }

      // 提取关键特征并添加权重
      const processedDescriptions = selectedCharacters
        .map((char) => {
          if (!char.description) return ''

          // 将角色名称添加到描述中，确保AI能识别角色
          // 使用括号和权重增强角色名称的重要性
          // return `(${char.name}:1.3), ${char.description}`
          return `(${char.name}), ${char.description}`
        })
        .filter(Boolean) // 过滤掉空描述

      // 合并所有选中角色的描述词，使用 BREAK 分隔符确保Stable Diffusion能正确识别多个角色
      if (processedDescriptions.length > 1) {
        // 多个角色时，使用 BREAK 连接符
        characterPrompts = processedDescriptions.join(' BREAK ')
      } else {
        // 单个角色时直接使用描述
        characterPrompts = processedDescriptions[0]
      }
    }

    // 智能合并提示词：确保原始提示词和角色描述词有效结合
    let finalPrompt = ''
    if (characterPrompts) {
      // 检查原始提示词是否已包含某些角色描述，避免重复
      const originalPrompt = shot.englishPrompt.trim()

      // 构建更自然的提示词组合
      // 1. 性别前缀提供场景中人物的基本构成
      // 2. 场景描述（原始提示词）具有较高权重
      // 3. 角色描述词提供具体角色的详细特征
      if (genderPrefix) {
        // 有性别前缀时，按照 性别前缀 + 场景描述 + 角色描述 的顺序组合
        finalPrompt = `${genderPrefix}${originalPrompt}, BREAK ${characterPrompts}`
      } else {
        // 无性别前缀时，直接组合场景描述和角色描述
        finalPrompt = `${originalPrompt}, BREAK ${characterPrompts}`
      }
    } else {
      finalPrompt = shot.englishPrompt
    }

    // 发送生成图片事件到父组件，包含合并后的提示词
    emit('generate-image', {
      ...updatedShot,
      finalPrompt
      // 移除batch_size参数，让后端从配置文件中读取
    })

    // 创建一个Promise来等待图片生成完成
    // 使用轮询方式检查图片是否已生成
    let checkInterval = 1000 // 初始检查间隔为1秒
    const maxInterval = 3000000 // 最大检查间隔为300秒

    while (checkCount < maxChecks) {
      await new Promise((resolve) => setTimeout(resolve, checkInterval))
      checkCount++

      // 动态调整检查间隔，随着等待时间增加而增加间隔，减少请求频率
      if (checkCount > 20) {
        checkInterval = Math.min(checkInterval * 1.2, maxInterval)
      }

      // 检查当前shot是否有新图片生成（与原始图片不同）
      if (props.shots[index].image && props.shots[index].image !== originalImage) {
        imageGenerated = true
        break // 新图片已生成，跳出循环
      }

      // 如果等待时间过长，显示提示但继续等待
      if (checkCount === 30) {
        ElMessage.info('图片生成中，请耐心等待...')
      }
    }

    // 如果生成了新图片，将其保存到variantImages数组
    if (imageGenerated) {
      // 检查shot是否仍在当前页面
      if (shotIndex !== -1 && props.shots[shotIndex]) {
        const currentShot = props.shots[shotIndex]
        const newImage = currentShot.image

        if (!currentShot.image) {
          currentShot.image = newImage           // 设置主图
          currentShot.variantImages.push(newImage)
          currentShot.selectedThumbnailIndex = 0 // ★默认选中第一张缩略图
        } else {
          currentShot.variantImages.push(newImage)
          currentShot.selectedThumbnailIndex = currentShot.variantImages.length - 1 // 新增图，选中新图
        }

        props.shots[shotIndex] = { ...currentShot }
        emit('update:shots', [...props.shots])
      } else {
        // 如果shot不在当前页面（可能因为分页切换），记录日志但不中断流程
        console.log('图片生成完成，但分镜不在当前页面，可能已切换分页')
        // 这里不需要更新UI，因为当用户切回该页面时，数据会从服务器重新加载
      }
    }


    // 如果超时且没有生成新图片，显示提示
    if (!imageGenerated && checkCount >= maxChecks) {
      ElMessage.warning('图片生成超时，请稍后再试')
      throw new Error('图片生成超时') // 抛出错误以便批量生成函数可以捕获并处理
    }
  } catch (error) {
    console.error('生成图片失败:', error)
    ElMessage.error('生成图片失败，请稍后重试')
    throw error // 向上传递错误，让批量生成函数可以捕获并处理
  } finally {
    // 只有当新图片已生成或超时后才重置generating状态
    if (shotIndex !== -1 && props.shots[shotIndex]) {
      // 如果shot在当前页面，更新UI
      const currentShot = props.shots[shotIndex]
      const hasNewImage = currentShot.image && currentShot.image !== originalImage

      if (hasNewImage || checkCount >= maxChecks) {
        currentShot.generating = false
        props.shots[shotIndex] = { ...currentShot }
        emit('update:shots', [...props.shots])
      }
    } else {
      // 如果shot不在当前页面，只更新shot对象本身的状态
      shotToUpdate.generating = false
    }
  }
}

// 切换主图片函数 - 点击缩略图时调用
const switchMainImage = (shot: Shot, thumbnailIndex: number) => {
  if (!shot.variantImages || thumbnailIndex >= shot.variantImages.length) return

  const index = props.shots.indexOf(shot)
  if (index === -1) return

  const updatedShot = { ...shot }

  // 设置主图为选中的缩略图
  updatedShot.image = updatedShot.variantImages[thumbnailIndex]

  // 设置当前选中的缩略图索引
  updatedShot.selectedThumbnailIndex = thumbnailIndex

  props.shots[index] = updatedShot
  emit('update:shots', [...props.shots])

  ElMessage.success('已切换主图片')
}


// 此函数保留用于兼容性，但不再在UI中显示按钮调用
// const handleGenerateVariants = async (shot: Shot) => {
//   // 确保generatingVariants属性已初始化
//   if (shot.generatingVariants === undefined) {
//     shot.generatingVariants = false
//   }

//   if (shot.generatingVariants) return
//   const index = props.shots.indexOf(shot)
//   if (index === -1) return

//   // 确保variantImages数组已初始化
//   if (!shot.variantImages) {
//     shot.variantImages = []
//   }

//   const updatedShot = { ...shot, generatingVariants: true }
//   props.shots[index] = updatedShot
//   emit('update:shots', [...props.shots])

//   try {
//     // 生成3张备选图片
//     const numVariants = 3

//     for (let i = 0; i < numVariants; i++) {
//       try {
//         // 发送生成图片事件到父组件
//         emit('generate-variants', updatedShot)

//         // 等待一段时间，让父组件有时间处理请求
//         await new Promise(resolve => setTimeout(resolve, 3000))

//         // 如果是最后一张图片，添加额外延迟以确保所有图片都已生成
//         if (i === numVariants - 1) {
//           await new Promise(resolve => setTimeout(resolve, 2000))
//         }
//       } catch (error) {
//         console.error(`生成第${i + 1}张备选图片失败:`, error)
//         break
//       }
//     }

//     // 确保状态更新触发视图刷新
//     emit('update:shots', [...props.shots])
//   } catch (error) {
//     console.error('生成备选图片失败:', error)
//   } finally {
//     // 重置generatingVariants状态
//     const currentShot = props.shots[index]
//     currentShot.generatingVariants = false
//     props.shots[index] = { ...currentShot }
//     emit('update:shots', [...props.shots])
//   }
// }

const handleBatchGenerate = async () => {
  if (batchGenerating.value) return
  batchGenerating.value = true

  // 收集所有需要生成图片的shot（不仅限于当前页面）
  // 从服务器获取的完整shots列表，而不仅仅是当前页面显示的
  const allShots = await getAllShots()
  const shotsToGenerate = allShots.filter((shot) => !shot.image)
  const totalShots = shotsToGenerate.length

  // 重置并显示进度条 - 确保percentage计算正确
  batchProgress.value = {
    visible: true,
    total: Math.max(totalShots, 1), // 确保分母至少为1，避免除以0
    current: 0,
    success: 0,
    failed: 0,
    failedShots: []
  }

  try {
    // 不再显示弹窗提示，改用悬浮进度条
    console.log(`开始批量生成 ${totalShots} 个分镜图片`)

    // 逐个生成图片，添加重试机制
    for (let i = 0; i < shotsToGenerate.length; i++) {
      const shot = shotsToGenerate[i]
      if (!shot.image) {
        // 更新当前处理的索引
        batchProgress.value.current = i + 1

        try {
          // 最多尝试2次
          let retryCount = 0
          const maxRetries = 1
          let success = false

          while (!success && retryCount <= maxRetries) {
            try {
              await handleGenerate(shot)
              success = true
              batchProgress.value.success++
            } catch (genError) {
              retryCount++
              if (retryCount <= maxRetries) {
                console.log(`生成分镜失败，正在重试(${retryCount}/${maxRetries})...`)
                // 重试前等待更长时间
                await new Promise((resolve) => setTimeout(resolve, 2000))
              } else {
                throw genError
              }
            }
          }

          // 添加延迟，避免API请求过于频繁，成功后延迟短一些
          await new Promise((resolve) => setTimeout(resolve, 800))
        } catch (shotError) {
          console.error(`生成分镜失败:`, shotError)
          const failedShotInfo = shot.originalText?.substring(0, 20) + '...'
          batchProgress.value.failedShots.push(failedShotInfo)
          batchProgress.value.failed++
          // 失败后添加更长的延迟，让服务器有时间恢复
          await new Promise((resolve) => setTimeout(resolve, 3000))
        }
      }
    }
  } catch (error) {
    console.error('批量生成图片失败:', error)
    // 不再弹出提示，而是在进度条中显示错误
  } finally {
    // 5秒后自动隐藏进度条
    setTimeout(() => {
      batchProgress.value.visible = false
    }, 5000)

    batchGenerating.value = false
    // 确保状态更新触发视图刷新
    emit('update:shots', [...props.shots])
  }
}

// 获取所有分镜（包括不在当前页面显示的）
const getAllShots = async () => {
  // 这里我们直接返回props.shots，因为在当前实现中，
  // 所有分镜数据都已经在父组件中加载并传递给了该组件
  // 如果实际情况中分镜数据是分页加载的，这里需要调用API获取所有分镜
  return props.shots
}

const handleEdit = (shot: Shot) => {
  ElMessageBox.prompt('编辑分镜描述词', '编辑', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputType: 'textarea',
    inputValue: shot.englishPrompt
  }).then(({ value }) => {
    if (value.trim()) {
      shot.englishPrompt = value.trim()
      shot.image = undefined
    }
  })
}

const handleDelete = (index: number) => {
  ElMessageBox.confirm('确定要删除这个分镜吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    props.shots.splice(index, 1)
    emit('update:shots', props.shots)
  })
}

const handleExport = () => {
  // 合并两种选择方式的结果：表格多选和图片点击选择
  // 1. 从表格selection-change事件获取的选中项
  const selectionChangeSelected = selectedShots.value || []
  // 2. 从props.shots中筛选出所有通过点击图片选中的项(selected为true的项)
  const manualSelected = props.shots.filter((shot) => shot.selected === true)

  // 合并两种选择方式，确保不重复
  const allSelectedShots = [...selectionChangeSelected]
  manualSelected.forEach((shot) => {
    if (!allSelectedShots.some((s) => s === shot)) {
      allSelectedShots.push(shot)
    }
  })

  // 更新selectedShots值
  selectedShots.value = allSelectedShots

  // 确定要导出的分镜：如果有选中的分镜，则导出选中的；否则导出全部
  const shotsToExport = selectedShots.value.length > 0 ? selectedShots.value : props.shots

  // 检查是否有未生成的图片
  const unGeneratedShots = shotsToExport.filter((shot) => !shot.image)
  if (unGeneratedShots.length > 0) {
    ElMessage.warning(`还有${unGeneratedShots.length}个分镜未生成图片，请先生成所有图片`)
    return
  }

  exportFolderName.value = `分镜导出_${new Date().toISOString().slice(0, 10)}`
  exportDialogVisible.value = true
}

const handleRegeneratePrompt = async (shot: Shot) => {
  // 确保regeneratingPrompt属性已初始化
  if (shot.regeneratingPrompt === undefined) {
    shot.regeneratingPrompt = false
  }

  if (shot.regeneratingPrompt) return
  const index = props.shots.indexOf(shot)
  if (index === -1) return

  // 创建shot的副本并设置regeneratingPrompt状态
  const updatedShot = { ...shot, regeneratingPrompt: true }
  props.shots[index] = updatedShot
  emit('update:shots', [...props.shots])

  try {
    // 发送重新生成描述词事件到父组件
    emit('regenerate-prompt', updatedShot)

    // 创建一个Promise来等待描述词生成完成
    // 使用轮询方式检查描述词是否已更新
    let checkCount = 0
    const maxChecks = 30 // 最多检查30次，约30秒

    while (checkCount < maxChecks) {
      await new Promise((resolve) => setTimeout(resolve, 1000)) // 每秒检查一次
      checkCount++

      // 检查当前shot的描述词是否已更新
      if (props.shots[index].englishPrompt !== shot.englishPrompt) {
        break // 描述词已更新，跳出循环
      }
    }

    // 确保状态更新触发视图刷新
    emit('update:shots', [...props.shots])
  } catch (error) {
    console.error('重新生成描述词失败:', error)
  } finally {
    // 重置regeneratingPrompt状态
    const currentShot = props.shots[index]
    currentShot.regeneratingPrompt = false
    props.shots[index] = { ...currentShot }
    emit('update:shots', [...props.shots])
  }
}

const handleSelectionChange = (selection: Shot[]) => {
  selectedShots.value = selection
}

const toggleImageSelection = (row: Shot) => {
  // 切换选中状态
  row.selected = !row.selected

  // 同步更新selectedShots数组，确保与表格选择状态保持一致
  if (row.selected) {
    // 如果是选中状态，且不在selectedShots中，则添加
    if (!selectedShots.value.some((shot) => shot === row)) {
      selectedShots.value.push(row)
    }
  } else {
    // 如果是取消选中状态，则从selectedShots中移除
    selectedShots.value = selectedShots.value.filter((shot) => shot !== row)
  }

  // 触发视觉反馈
  const shotElement = document.querySelector(
    `.image-container[data-shot-id="${props.shots.indexOf(row)}"]`
  )
  if (shotElement) {
    shotElement.classList.add('selection-animation')
    setTimeout(() => {
      shotElement.classList.remove('selection-animation')
    }, 300)
  }

  // 更新shots数组，触发视图更新
  emit('update:shots', [...props.shots])
}

const clearSelection = () => {
  // 清除所有选中状态
  props.shots.forEach((shot) => {
    shot.selected = false
  })

  // 清空selectedShots数组
  selectedShots.value = []

  // 更新shots数组，触发视图更新
  emit('update:shots', [...props.shots])

  // 显示提示信息
  ElMessage.info('已清除所有选择')
}

// 导出功能已整合到handleExport函数中

// 显示备选图片对话框
// const showVariants = (shot: Shot) => {
//   currentShot.value = shot
//   currentShotIndex.value = props.shots.indexOf(shot)
//   variantsDialogVisible.value = true
// }

const confirmExport = async () => {
  if (!exportFolderName.value.trim()) {
    ElMessage.warning('请输入导出目录名称')
    return
  }

  // 确定要导出的分镜：如果有选中的分镜，则导出选中的；否则导出全部
  const shotsToExport = selectedShots.value.length > 0 ? selectedShots.value : props.shots

  // 检查要导出的分镜是否都已生成图片
  const unGeneratedShots = shotsToExport.filter((shot) => !shot.image)
  if (unGeneratedShots.length > 0) {
    ElMessage.warning(`还有${unGeneratedShots.length}个分镜未生成图片，请先生成所有图片`)
    return
  }

  exporting.value = true

  try {
    // 使用导出服务
    await exportApi.exportImages(exportFolderName.value, shotsToExport)

    ElMessage.success('图片导出成功')
    exportDialogVisible.value = false

    // 导出成功后清除选择状态
    if (selectedShots.value.length > 0) {
      clearSelection()
    }
  } catch (error: any) {
    console.error('导出图片失败:', error)
    ElMessageBox.alert('导出图片失败: ' + (error.message || error), '错误')
  } finally {
    exporting.value = false
  }
}

// 处理角色标签变更
const handleCharacterTagsChange = (shot: Shot) => {
  // 当角色标签变更时，清除已生成的图片
  shot.image = undefined
  shot.variantImages = []

  // 获取选中角色的描述词预览
  if (shot.characterTags?.length) {
    const selectedCharacters = characters.value.filter((char) =>
      shot.characterTags?.includes(char.name)
    )
    // 显示选中角色数量
    const characterCount = selectedCharacters.length
    if (characterCount > 0) {
      ElMessage.success(`已选择${characterCount}个角色，生成图片时将自动合并角色描述词`)
    } else {
      ElMessage.info('未选择角色，将使用原始提示词生成图片')
    }
  }

  emit('update:shots', [...props.shots])
}

// 组件挂载时加载角色列表
onMounted(() => {
  loadCharacters()
})

// 处理向上合并分镜
const handleMergeUp = (index: number) => {
  if (index <= 0 || index >= props.shots.length) return

  // 获取当前分镜和上一个分镜
  const currentShot = props.shots[index]
  const prevShot = props.shots[index - 1]

  // 合并原文描述和英文提示词
  const mergedShot = {
    ...prevShot,
    originalText: `${prevShot.originalText} ${currentShot.originalText}`,
    englishPrompt: `${prevShot.englishPrompt}, ${currentShot.englishPrompt}`,
    // 清除图片，因为内容已经变更
    image: undefined,
    variantImages: []
  }

  // 创建新的分镜数组，移除当前分镜，更新上一个分镜
  const updatedShots = [...props.shots]
  updatedShots[index - 1] = mergedShot
  updatedShots.splice(index, 1)

  // 发送更新事件
  emit('update:shots', updatedShots)
}

// 处理向下合并分镜
const handleMergeDown = (index: number) => {
  if (index < 0 || index >= props.shots.length - 1) return

  // 获取当前分镜和下一个分镜
  const currentShot = props.shots[index]
  const nextShot = props.shots[index + 1]

  // 合并原文描述和英文提示词
  const mergedShot = {
    ...currentShot,
    originalText: `${currentShot.originalText} ${nextShot.originalText}`,
    englishPrompt: `${currentShot.englishPrompt}, ${nextShot.englishPrompt}`,
    // 清除图片，因为内容已经变更
    image: undefined,
    variantImages: []
  }

  // 创建新的分镜数组，移除下一个分镜，更新当前分镜
  const updatedShots = [...props.shots]
  updatedShots[index] = mergedShot
  updatedShots.splice(index + 1, 1)

  // 发送更新事件
  emit('update:shots', updatedShots)
}
</script>

<style scoped>
.storyboard-image-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  height: 100%;
}

.storyboard-table {
  flex: 1;
  overflow: auto;
  max-height: none !important;
  background: var(--el-bg-color);
  border-radius: var(--el-border-radius-base);
  box-shadow: var(--el-box-shadow-light);
}

.text-content,
.prompt-content {
  max-width: 100%;
  word-break: break-all;
  padding: 0.5rem;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.audio-controls {
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.audio-player {
  width: 100%;
  max-width: 250px;
  height: 30px;
}

.clone-voice-controls {
  margin-top: 0.5rem;
  display: flex;
  justify-content: center;
}

.speech-to-text-controls {
  margin-top: 0.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.recording-status {
  font-size: 12px;
  color: var(--el-color-danger);
  text-align: center;
  min-height: 18px;
}

.regenerate-button {
  align-self: flex-end;
}

.prompt-input {
  width: 100%;
  height: 100%;
  margin: 0;
}

.prompt-input :deep(.el-textarea__inner) {
  height: 100%;
  min-height: 150px;
  resize: none;
}

.image-preview,
.generate-placeholder,
.image-variants {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0.5rem;
}


.batch-actions {
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  margin-top: 1rem;
  padding: 0.5rem;
  background: var(--el-bg-color-overlay);
  border-radius: var(--el-border-radius-base);
}

/* 悬浮进度显示组件样式 */
.floating-progress {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 350px;
  background: var(--el-bg-color);
  border-radius: var(--el-border-radius-base);
  box-shadow: var(--el-box-shadow);
  z-index: 9999;
  padding: 15px;
  border: 1px solid var(--el-border-color);
}

.progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.progress-title {
  font-weight: bold;
  font-size: 16px;
}

.close-button {
  padding: 2px;
}

.progress-content {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.progress-stats {
  display: flex;
  justify-content: space-between;
  font-size: 14px;
}

.success-count {
  color: var(--el-color-success);
}

.failed-count {
  color: var(--el-color-danger);
}

.failed-shots {
  margin-top: 5px;
  border-top: 1px solid var(--el-border-color-lighter);
  padding-top: 5px;
}

.failed-title {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 5px;
  color: var(--el-color-danger);
}

.failed-list {
  max-height: 100px;
  overflow-y: auto;
  font-size: 12px;
}

.failed-item {
  padding: 3px 0;
  border-bottom: 1px dashed var(--el-border-color-lighter);
}

.image-preview {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 1rem 0;
  gap: 0.5rem;
}

.image-container {
  position: relative;
  width: 160px;
  height: 160px;
  border-radius: 8px;
  overflow: hidden;
  transition: all 0.3s ease;
  border: 2px solid transparent;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  margin-bottom: 8px;
}

.image-container:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.15);
}

.selected-image {
  border: 3px solid #409eff;
  box-shadow: 0 0 12px rgba(64, 158, 255, 0.6);
}

.completed-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  background-color: #67c23a;
  color: white;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: bold;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

/* 缩略图预览区样式 */
.thumbnails-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
  justify-content: center;
  width: 100%;
  max-width: 220px;
}

.thumbnail {
  position: relative;
  width: 50px;
  height: 50px;
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  border: 1px solid #dcdfe6;
  transition: all 0.2s ease;
}

.thumbnail {
  position: relative;
}

.thumbnail:hover {
  transform: scale(1.05);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  border-color: #409eff;
}

.active-thumbnail {
  border: 2px solid #409eff;
  box-shadow: 0 0 8px rgba(64, 158, 255, 0.6);
}

.thumbnail-selected {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 16px;
  height: 16px;
  background-color: #409eff;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  font-size: 10px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

@keyframes selectionPulse {
  0% {
    transform: scale(1);
    box-shadow: 0 0 12px rgba(64, 158, 255, 0.6);
  }
  50% {
    transform: scale(1.03);
    box-shadow: 0 0 16px rgba(64, 158, 255, 0.8);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 12px rgba(64, 158, 255, 0.6);
  }
}

.selection-animation {
  animation: selectionPulse 0.3s ease;
}

.selection-indicator {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 24px;
  height: 24px;
  background-color: var(--el-color-primary);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  font-size: 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.selection-control {
  position: absolute;
  bottom: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  background-color: rgba(64, 158, 255, 0.8);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: white;
  font-size: 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  cursor: pointer;
  transition: all 0.3s ease;
  z-index: 10;
}

.selection-control:hover {
  transform: scale(1.1);
  background-color: var(--el-color-primary);
}

.generate-placeholder {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 160px;
  width: 160px;
  border-radius: 8px;
  background-color: var(--el-fill-color-lighter);
  margin: 0 auto;
}

.image-variants {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 160px;
  gap: 0.5rem;
}

.generate-variants-btn,
.view-variants-btn {
  width: 100%;
  margin-bottom: 5px;
}

.batch-actions {
  display: flex;
  justify-content: center;
  gap: 1rem;
  padding: 1rem 0;
  border-top: 1px solid var(--el-border-color-light);
  margin-top: 1rem;
}

.image-actions {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
}

.export-dialog {
  margin-top: 1rem;
}

.selection-info {
  margin-left: auto;
  color: var(--el-text-color-secondary);
}

/* 分页容器样式 */
.pagination-container {
  display: flex;
  justify-content: center;
  margin-top: 1rem;
  padding: 0.5rem;
}

/* 备选图片样式 */
.variant-count {
  margin-top: 0.5rem;
}

.variants-container {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.variants-header {
  margin-bottom: 1rem;
  padding: 1rem;
  background-color: var(--el-fill-color-light);
  border-radius: 8px;
}

.variants-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1.5rem;
  margin-bottom: 1.5rem;
}

.variant-item {
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  border: 2px solid var(--el-border-color);
  border-radius: 12px;
  padding: 1.2rem;
  background-color: var(--el-bg-color-overlay);
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}

.variant-item:hover {
  transform: translateY(-3px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
  border-color: #409eff;
}

.variant-item.hover-effect:hover {
  border-color: #409eff;
}

.variant-image-container {
  position: relative;
  width: 100%;
  height: 220px;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.current-image {
  border: 3px solid #409eff;
  background-color: rgba(64, 158, 255, 0.05);
  box-shadow: 0 0 12px rgba(64, 158, 255, 0.4);
}

.current-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  background-color: var(--el-color-primary);
  color: white;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: bold;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.variant-actions {
  display: flex;
  justify-content: center;
  margin-top: 0.8rem;
}

.variants-actions {
  display: flex;
  justify-content: center;
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--el-border-color-light);
}

.character-option {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
}

:deep(.el-select-dropdown__item) {
  padding: 8px 12px;
  height: 32px;
}

:deep(.el-select-dropdown__wrap) {
  max-height: 300px;
}

.tags-content {
  padding: 0.5rem;
}

.column-header-with-action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.refresh-button {
  padding: 4px;
  font-size: 12px;
  height: 24px;
  width: 24px;
}

.refresh-button i {
  font-size: 12px;
}

.custom-btn-group {
  margin-top: 8px;
}

</style>

